/**
	Pulsar engine. Core.
	Additional string support.

	Copyright (C) 2013-2014 Dmitry Dolgov

	This program is free software; you can redistribute it and/or modify it under the terms of the
	GNU General Public License as published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.
		
	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
	See the GNU General Public License for more details.
*/

/**
	Calculate length of string (in chars, without last '\0')
*/
inline pl_uint32 pl_strlen(const pl_char* str)
{
	PL_ASSERTE(str != NULL, PL_T("Wrong string source"));

#if defined(PL_ANSI)
	return (pl_uint32)strlen(str);
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
	return (pl_uint32)wcslen(str);
#else
#error "Unknown String type specification"
#endif
}

/**
	Calculate length of string (in chars, until termChar)
*/
inline pl_uint32 pl_strlen(const pl_char* str, pl_char termChar)
{
	pl_uint32 pos;

	PL_ASSERTE(str != NULL, PL_T("Wrong string source"));
	for (pos=0; ; pos++)
	{
		if (str[pos] == termChar)
		{
			return pos+1;
		}
		if (str[pos] == PL_T('\0'))
		{
			break;
		}
	}
	return pos;
}

/**
	Duplicate a string
*/
inline pl_char* pl_strdup(const pl_char* str)
{
#if defined(PL_ANSI)
	return strdup(str);
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
	pl_uint32 size=(pl_strlen(str)+1)*sizeof(pl_char);
	pl_char* dest = (pl_char*)malloc(size);
	memcpy(dest, str, size);
	return dest;
#else
#error "Unknown String type specification"
#endif
}

/**
	Compare strings like strcmp()
*/
inline int pl_strcmp(const pl_char* str1, const pl_char* str2)
{
	PL_ASSERTE(str1 != NULL && str2 != NULL, PL_T("Wrong String source"));

#if defined(PL_ANSI)
	return strcmp(str1, str2);
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
	return wcscmp(str1, str2);
#else
#error "Unknown String type specification"
#endif
}

/**
	Concatenate strings like strcat()
*/
inline pl_char* pl_strcat(pl_char* destStr, const pl_char* srcStr)
{
	PL_ASSERTE(destStr != NULL && srcStr != NULL, PL_T("Wrong String source"));

#if defined(PL_ANSI)
	return strcat(destStr, srcStr);
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
	return wcscat(destStr, srcStr);
#else
#error "Unknown String type specification"
#endif
}
/**
	Compare strings like strncmp()
*/
inline int pl_strncmp(const pl_char* str1, const pl_char* str2, int count)
{
#if defined(PL_ANSI)
	return strncmp(str1, str2, count);
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
	return wcsncmp(str1, str2, count);
#else
#error "Unknown String type specification"
#endif
}

/**
	Compare strings like stricmp()
*/
inline int pl_stricmp(const pl_char* str1, const pl_char* str2)
{
	PL_ASSERTE(str1 != NULL && str2 != NULL, PL_T("Wrong String source"));

#if defined(PL_ANSI)
#if defined(PL_LINUX)
	return strcasecmp(str1, str2);
#else
	return stricmp(str1, str2);
#endif
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
	return wcsicmp(str1, str2);
#else
#error "Unknown String type specification"
#endif
}

/**
	Compare strings like strnicmp()
*/
inline int pl_strnicmp(const pl_char* str1, const pl_char* str2, int count)
{
#if defined(PL_ANSI)
#if defined(PL_LINUX)
	return strncasecmp(str1, str2, count);
#else
	return strnicmp(str1, str2, count);
#endif
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
#if defined(PL_LINUX)

	pl_char f;
	pl_char l;

	do
	{
		f = towlower(*(str1++));
		l = towlower(*(str2++));
	}
	while (--count && f && (f == l));

	return f - l;
#else
	return wcsnicmp(str1, str2, count);
#endif
#else
#error "Unknown String type specification"
#endif
}


/**
	Copy string like strcpy()
*/
inline pl_char* pl_strcpy(pl_char* destStr, const pl_char* srcStr)
{
	PL_ASSERTE(destStr != NULL && srcStr != NULL, PL_T("Wrong String source"));

#if defined(PL_ANSI)
	return strcpy(destStr, srcStr);
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
	return wcscpy(destStr, srcStr);
#else
#error "Unknown String type specification"
#endif
}

/**
	Copy string like strncpy()
*/
inline pl_char* pl_strncpy(pl_char* destStr, const pl_char* srcStr, int size)
{
	PL_ASSERTE(destStr != NULL && srcStr != NULL, PL_T("Wrong String source"));

#if defined(PL_ANSI)
	return strncpy(destStr, srcStr, size);
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
	return wcsncpy(destStr, srcStr, size);
#else
#error "Unknown String type specification"
#endif
}

/**
	Find substring like strstr()
*/
inline const pl_char* pl_strstr(const pl_char* str, const pl_char* substr)
{
#ifdef PL_ANSI
	return strstr(str, substr);
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
	return wcsstr(str, substr);
#else
#error "Unknown String type specification"
#endif
}

inline pl_char* pl_strstr(pl_char* str, const pl_char* substr)
{
#ifdef PL_ANSI
	return strstr(str, substr);
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
	return wcsstr(str, substr);
#else
#error "Unknown String type specification"
#endif
}


/**
	Find character like strchr()
*/
inline const pl_char* pl_strchr(const pl_char* str, pl_char c)
{
	PL_ASSERTE(str != NULL, PL_T("Wrong String source"));

#if defined(PL_ANSI)
	return strchr(str, c);
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
	return wcschr(str, c);
#else
#error "Unknown String type specification"
#endif
}

inline pl_char* pl_strchr(pl_char* str, pl_char c)
{
	PL_ASSERTE(str != NULL, PL_T("Wrong String source"));

#if defined(PL_ANSI)
	return strchr(str, c);
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
	return wcschr(str, c);
#else
#error "Unknown String type specification"
#endif
}

/**
	Check isspace()
*/
inline int pl_isspace(pl_char c)
{
	if (c < 1 || (pl_uint32)c > 127)
	{
		return false;
	}

#if defined(PL_ANSI)
	return isspace( (pl_uint32) c);
#elif defined(PL_UNICODE) || defined(PL_UNICODE32)
	return iswspace(c);
#else
#error "Unknown String type specification"
#endif
}

/**
	Convert to uppercase
*/
inline pl_char pl_toupper(pl_char c)
{
	if (c < 1 || (pl_uint32)c > 127)
	{
		return c;
	}
#if defined(PL_LINUX)
	return static_cast<pl_char>(_toupper((pl_uint8)c));
#elif defined(PL_WINDOWS) || defined(PL_WINDOWS64)
	return static_cast<pl_char>(toupper((pl_uint8)c));
#else
	#error "Undefined OS"
#endif
}

/**
	Convert to lowercase
*/
inline pl_char pl_tolower(pl_char c)
{
	if (c < 1 || (pl_uint32)c > 127)
	{
		return c;
	}

#if defined(PL_LINUX)
	return static_cast<pl_char>(_tolower((pl_uint8)c));
#elif defined(PL_WINDOWS) || defined(PL_WINDOWS64)
	return static_cast<pl_char>(tolower((pl_uint8)c));
#else
	#error "Undefined OS"
#endif
}

/**
	Check digits
*/
inline bool pl_isdigit(pl_char c)
{
	if (c < 1 || (pl_uint32)c > 127)
	{
		return false;
	}

	return isdigit((pl_uint8)c) ? true : false;
}

/**
	Check hexdecimal digits
*/
inline bool pl_isxdigit(pl_char c)
{
	if (c < 1 || (pl_uint32)c > 127)
	{
		return false;
	}

	return isxdigit((pl_uint8)c) ? true : false;
}

/**
	Check isaplha
*/
inline bool pl_isalpha(pl_char c)
{
	if (c < 1 || (pl_uint32)c > 127)
	{
		return false;
	}

	return isalpha((pl_uint8)c) ? true : false;
}

/**
	Check isalpga or isdigit
*/
inline bool pl_isalnum(pl_char c)
{
	if (c < 1 || (pl_uint32)c > 127)
	{
		return false;
	}

	return isalnum((pl_uint8)c) ? true : false;
}

//
// End of file 'pulsar_string_std.h'
//
